#include "LevelBuilder.h"

LevelBuilder* LevelBuilder::instance = NULL;

LevelBuilder::LevelBuilder() {
    //ctor
}

LevelBuilder::~LevelBuilder() {
    delete instance;
}

LevelBuilder* LevelBuilder::getInstance() {
    if(instance == NULL) {
        instance = new LevelBuilder();
    }

    return instance;
}

World* LevelBuilder::loadLevel(std::string levelFile) {
    World* world = new World("World");

    GameObject* currentObject;
    std::vector<std::string> lineVector;

    std::string line;
    std::ifstream file(levelFile.c_str());

    if(file.is_open()) {
        while(std::getline(file, line)) {
            if(line[0] == '[') {
                line.erase(0, 1); // Verwijder [
                line.erase(line.length() - 1, line.length()); // Verwijder ]

                split(line, lineVector, '.');

                if(lineVector.size() == 1) {
                    currentObject = ObjectFactory::getInstance()->parseObject(line);

                    //Global::getWorld()->getTree()->add(currentObject);
                    world->add(currentObject);
                } else if(lineVector.size() == 2) {
                    currentObject = ObjectFactory::getInstance()->parseObject(lineVector.at(1));
                    //Global::getWorld()->getTree()->add(currentObject);
                    world->add(currentObject);
                }
            } else {
                split(line, lineVector, ' ');

                if(line[0] == 't') {
                    std::string texture = "game/assets/textures/"+ lineVector.at(1);
                    currentObject->setColorMap(Texture::load(texture.c_str()));
                } else if(line[0] == 'm') {
                    std::string mesh = "game/assets/models/"+ lineVector.at(1);
                    currentObject->setMesh(Mesh::load(mesh.c_str()));
                } else if(line[0] == 'p') {
                    glm::vec3 scale(1.0, 1.0, 1.0);

                    if(lineVector.size() == 9) {  // Scale
                        scale = glm::vec3(atof(lineVector.at(8).c_str()));
                    }

                    if(lineVector.size() == 11) {  // Scale
                        scale.x = atof(lineVector.at(8).c_str());
                        scale.y = atof(lineVector.at(9).c_str());
                        scale.z = atof(lineVector.at(10).c_str());
                    }

                    if(scale.x != 1.0f || scale.y != 1.0f || scale.z != 1.0f) {
                        currentObject->setTransform(glm::scale(glm::mat4(1.0f), scale));
                    }

                    float angle = 0.0f;
                    glm::vec3 rotation(0.0, 0.0, 0.0);

                    if(lineVector.size() >= 8) {  // Rotatie
                        angle = atof(lineVector.at(4).c_str());
                        rotation.x = atof(lineVector.at(5).c_str());
                        rotation.y = atof(lineVector.at(6).c_str());
                        rotation.z = atof(lineVector.at(7).c_str());
                    }

                    if(angle != 0.0f) {
                        currentObject->rotate(angle, rotation);
                    }

                    glm::vec3 position(0.0, 0.0, 0.0);

                    if(lineVector.size() >= 4) {  // Positie
                        position.x = atof(lineVector.at(1).c_str());
                        position.y = atof(lineVector.at(2).c_str());
                        position.z = atof(lineVector.at(3).c_str());
                    }

                    currentObject->setLocation(position);
                } else if(line[0] == 'c') {
                    if(lineVector.at(1) == "sphereCollider") {
                        currentObject->setCollider(new SphereCollider(currentObject, currentObject->getMesh()->computeRadius()));
                    }
                } else if(line[0] == 'l') {

                } else if(line[0] == 'r') {
                    //GameObject* parent = currentObject->getParent();
                    for(int i = 1; i < atoi(lineVector.at(1).c_str()); i++) {
                        std::stringstream stream;
                        stream << currentObject->getName() << "-" << (i + 1);

                        GameObject* newObject = ObjectFactory::getInstance()->parseObject(currentObject->getName());
                        newObject->setName(stream.str());

                        world->add(newObject);
                        stream.str("");
                    }

                    world->setAsteroidsLeft(atoi(lineVector.at(1).c_str()));
                }
            }
        }
    }

    return world;
}

bool LevelBuilder::startsWith(std::string text, std::string toCheck) {
    return std::mismatch(text.begin(), text.end(), toCheck.begin()).first == text.end();
}

unsigned int LevelBuilder::split(const std::string& text, std::vector<std::string>& output, char delimeter) {
    unsigned int position = text.find(delimeter);
    unsigned int initialPosition = 0;
    output.clear();

    // Decompose statement
    while(position != std::string::npos) {
        output.push_back(text.substr(initialPosition, position - initialPosition));
        initialPosition = position + 1;

        position = text.find(delimeter, initialPosition);
    }

    // Add the last one
    output.push_back(text.substr(initialPosition, std::min(position, text.size()) - initialPosition + 1));
    return output.size();
}

bool LevelBuilder::isNumber(std::string line) {
    return (atof(line.c_str()));
}
